import json

from common.entitys.caiptal import Flow, TransCode2
from common.entitys.train import TrainModel
from service import training_model
from utils import caiptal_util, price_util, k_util_v1, macd_util_v1, form_util, ave_util, cache_util, date_util
from utils.form_util import FormInfo
from database.mapper import stock_day_k as sdk


class MonitorType:
    one = 1  #
    two = 2  #
    thr = 3  #
    four = 4  # 定时任务C结果
    five = 5  # 实例结果记录


class TriggerType:
    zero = 0  # 无触发
    one = 1  # 突破5日均线
    two = 2  # 突破10日均线
    thr = 3  # 跌破5日均线
    four = 4  # 跌破10日均线
    five = 5  # 主力资金买
    six = 6  # 主力资金卖
    seven = 7  # macd v
    eight = 8  # macd /
    nine = 9  # macd \
    ten = 10  # macd ^


class Monitor:
    def __init__(self, code: str, name: str):
        self.code: str = code
        self.name: str = name
        self.kp: float = 0
        self.last_max_price: float = 0  # 上一个交易日最高价格
        self.last_min_price: float = 0  # 上一个交易日最低价格
        self.last_sp_price: float = 0  # 上一个交易日收盘
        self.rt_price: float = 0
        self.rt_main_io: float = 0
        self.rt_main_i: float = 0
        self.rt_main_o: float = 0
        self.ave5: float = 0
        self.ave10: float = 0
        self.rt_k_line = None
        self.break_ave5: bool = False  # 是否突破5日均线
        self.break_ave10: bool = False  # 是否突破10日均线
        self.below_ave5: bool = False  # 是否跌破5日均线
        self.below_ave10: bool = False  # 是否跌破10日均线
        self.main_io_buy: bool = False  # 主力资金买
        self.main_io_sell: bool = False  # 主力资金卖
        self.prompt: bool = False  # 提示标识
        self.update_flag: bool = False  # 是否更新数据库
        self.main_io_buy_model: str = ''  # 主力资金买
        self.main_io_sell_model: str = ''  # 主力资金卖
        self.form_info: FormInfo = None
        self.form_macd3 = None
        self.rt_flow: Flow = None  # 实时的资金流动
        self.flow_sum_dict: dict = None  # 累计资金流
        self.train_model: TrainModel = None  # 训练模型
        self.rq: str = date_util.get_date_str()
        self.task_time: str = date_util.get_date_time_str()
        self.bs: int = 0  # 0:无操作,1:买,2:卖
        self.cir_val: int = 0  # 流通市值
        self.rt_info: dict = {}  # 实时信息
        self.strategy_info: list = []  # 配置触发消息

    # 获取累计资金流
    def get_main_io_days(self, days: int):
        return self.get_flow_sum_dict().get(days)

    # 获取均线价格
    def get_ave_price(self, days: int):
        return ave_util.ave_line_price(self.get_rt_k_line(days), days)

    # 累计资金流
    def get_flow_sum_dict(self):
        if self.flow_sum_dict is None:
            self.get_train_model()
        return self.flow_sum_dict

    def get_train_model(self):
        if self.train_model is None:
            self.train_model = TrainModel(self.code)
            cache_key = 'task_c' + self.code + 'train_info'
            cache_train_info = cache_util.get_cache_expire(cache_key)
            if cache_train_info is None:
                train_info = training_model.train(self.code)
                zf_price = round(
                    (train_info.get('end_price') - train_info.get('beg_price')) / train_info.get('beg_price'), 4)
                zf_earn = round((train_info.get('champion_max') - 100000) / 100000, 4)
                self.train_model.buy_ls = train_info.get('buy_ls')
                self.train_model.sel_ls = train_info.get('sel_ls')
                self.train_model.buy_jfg = train_info.get('buy_jfg')
                self.train_model.sel_jfg = train_info.get('sel_jfg')
                amt_sum_sort = train_info['amt_sum_sort'][0:10]
                amt_sum_sort.reverse()
                self.train_model.zf_earn_sort_m_io = amt_sum_sort

                # 全持收益
                self.train_model.zf_price_m_io = zf_price
                self.train_model.zf_earn_m_io = zf_earn
                self.train_model.best_module_m_io = train_info.get('champion_max_inv')
                self.flow_sum_dict = train_info['flow_sum_dict']

                cache_util.set_cache_expire(cache_key, {'best_module': train_info.get('champion_max_inv'),
                                                        'flow_sum_dict': train_info['flow_sum_dict'],
                                                        'zf_price_m_io': self.train_model.zf_price_m_io,
                                                        'zf_earn_sort_m_io': self.train_model.zf_earn_sort_m_io,
                                                        'buy_ls': self.train_model.buy_ls,
                                                        'sel_ls': self.train_model.sel_ls,
                                                        'buy_jfg': self.train_model.buy_jfg,
                                                        'sel_jfg': self.train_model.sel_jfg,
                                                        'zf_earn_m_io': self.train_model.zf_earn_m_io},
                                            int((date_util.datetime2timestamp(
                                                date_util.get_date_str() + ' 15:00:00') - date_util.get_timestamp_now()) / 60))
            else:
                self.train_model.best_module_m_io = cache_train_info.get('best_module')
                self.train_model.zf_price_m_io = cache_train_info.get('zf_price_m_io')
                self.train_model.zf_earn_m_io = cache_train_info.get('zf_earn_m_io')
                self.train_model.zf_earn_sort_m_io = cache_train_info.get('zf_earn_sort_m_io')
                self.flow_sum_dict = cache_train_info.get('flow_sum_dict')
                self.train_model.buy_ls = cache_train_info.get('buy_ls')
                self.train_model.sel_ls = cache_train_info.get('sel_ls')
                self.train_model.buy_jfg = cache_train_info.get('buy_jfg')
                self.train_model.sel_jfg = cache_train_info.get('sel_jfg')
        return self.train_model

    # 分析实时形态
    # 获取最佳形态
    def get_form_info(self):
        if self.form_info is None:
            self.form_info = FormInfo()
            key = 'task_c_bask_form_' + self.code
            best_form_info = cache_util.get_cache_expire(key)
            if best_form_info is None:
                self.form_info = form_util.get_best_form(form_util.parse_x_reverse(self.get_rt_k_line(15), 'sp'))
                cache_util.set_cache_expire(key, json.dumps(self.get_form_info(), default=lambda o: o.__dict__),
                                            int((date_util.datetime2timestamp(
                                                date_util.get_date_str() + ' 15:00:00') - date_util.get_timestamp_now()) / 60))
            else:
                self.form_info.__dict__ = eval(best_form_info)
        return self.form_info

    # 实时价格
    def get_rt_price(self):
        if self.rt_price == 0:
            self.rt_price = self.get_rt_info().get(TransCode2.price)
        return self.rt_price

    # 主力净流入
    def get_rt_main_io(self):
        if self.rt_main_io == 0:
            self.rt_main_io = self.get_rt_info().get(TransCode2.main_io)
        return self.rt_main_io

    # 主力流入
    def get_rt_main_i(self):
        if self.rt_main_i == 0:
            self.rt_main_i = self.get_rt_info().get(TransCode2.main_i)
        return self.rt_main_i

    # 主力流出
    def get_rt_main_o(self):
        if self.rt_main_o == 0:
            self.rt_main_o = self.get_rt_info().get(TransCode2.main_o)
        return self.rt_main_o

    # 流通市值
    def get_cir_val(self):
        if self.cir_val == 0:
            self.cir_val = self.get_rt_info().get(TransCode2.ltsz)
        return self.cir_val

    # 实时资金流
    def get_rt_flow(self):
        if self.rt_flow is None:
            self.rt_flow = caiptal_util.get_flow(self.code)  # :http查询
        return self.rt_flow

    # 实时信息
    def get_rt_info(self):
        if len(self.rt_info) == 0:
            self.rt_info = price_util.rt_info(self.code)
        return self.rt_info

    # 实时k线信息
    def get_rt_k_line(self, size):
        if self.rt_k_line is None or len(self.rt_k_line) < size:
            ks = k_util_v1.day_k_size_rt(self.code, size, self.get_rt_price())
            for k in ks:
                k['rq'] = date_util.date_to_str(k.get('rq'), '%Y-%m-%d')
                k['up_time'] = ''
            self.rt_k_line = ks
        return self.rt_k_line[0:size]

    # 当前开盘价
    def get_kp(self):
        if self.kp == 0:
            self.kp = self.get_rt_k_line(16)[0].get('kp')
        return self.kp

    # 上一个交易日最高价格
    def get_last_max_price(self):
        if self.last_max_price == 0:
            self.last_max_price = self.get_rt_k_line(16)[1].get('max')
        return self.last_max_price

    # 上一个交易日最低价格
    def get_last_min_price(self):
        if self.last_min_price == 0:
            self.last_min_price = self.get_rt_k_line(16)[1].get('min')
        return self.last_min_price

    # 上一个交易日收盘
    def get_last_sp_price(self):
        if self.last_sp_price == 0:
            self.last_sp_price = self.get_rt_k_line(16)[1].get('sp')
        return self.last_sp_price

    # 5日均线价
    def get_ave5(self):
        if self.ave5 == 0:
            self.ave5 = ave_util.ave_line_price(self.get_rt_k_line(16)[0: 5], 5)
        return self.ave5

    # 10日均线价
    def get_ave10(self):
        if self.ave10 == 0:
            self.ave10 = ave_util.ave_line_price(self.get_rt_k_line(16)[0: 10], 10)
        return self.ave10

    # 最近3日macd形态
    def get_form_macd3(self):
        if self.form_macd3 is None:
            macd_list3 = macd_util_v1.get_macd_rt(self.code, 3, self.rq, self.rt_price)
            self.form_macd3 = form_util.thr_form(form_util.parse_x_reverse(macd_list3, 'macd'))
        return self.form_macd3

    # 获取所有的k线
    def get_all_k_line(self):
        if self.rt_k_line is None or len(self.rt_k_line) < 1000:
            ks = sdk.select_all_desc(self.code)
            ks[0]['sp'] = self.get_rt_price()
            if self.get_rt_price() > ks[0]['max']:
                ks[0]['max'] = self.get_rt_price()
                sdk.update(ks[0])
            if self.get_rt_price() < ks[0]['min']:
                ks[0]['min'] = self.get_rt_price()
                sdk.update(ks[0])
            for k in ks:
                k['rq'] = date_util.date_to_str(k.get('rq'), '%Y-%m-%d')
                k['up_time'] = ''
            self.rt_k_line = ks
        return self.rt_k_line

    def __repr__(self):
        return repr((self.code, self.name, self.rt_price,
                     self.main_io_buy_model, self.main_io_sell_model, self.form_macd3,
                     self.break_ave5, self.break_ave10, self.below_ave5,
                     self.below_ave10, self.main_io_buy, self.main_io_sell))
